package com.hjh.usb.accessory.communication

import com.elvishew.xlog.XLog
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import java.io.File
import java.io.OutputStream

class AOASender(
    private val mutex: Mutex,
    private val outputStreamProvider: () -> OutputStream?,
    private val scope: CoroutineScope
) {
    companion object {
        private const val BUFFER_SIZE = 1024
        private const val ACK_TIMEOUT = 60_000L
        private const val MAX_RETRIES = 3
    }

    private data class PacketTask(
        val data: ByteArray,
        val retryCount: Int = 0,
        val deferred: CompletableDeferred<Boolean>
    ) {
        override fun equals(other: Any?): Boolean {
            if (this === other) return true
            if (javaClass != other?.javaClass) return false

            other as PacketTask

            if (retryCount != other.retryCount) return false
            if (!data.contentEquals(other.data)) return false
            if (deferred != other.deferred) return false

            return true
        }

        override fun hashCode(): Int {
            var result = retryCount
            result = 31 * result + data.contentHashCode()
            result = 31 * result + deferred.hashCode()
            return result
        }
    }

    private val sendChannel = Channel<PacketTask>(capacity = 32)
    private val ackWaiters = Channel<CompletableDeferred<Unit>>(capacity = 32)

    fun start() {
        startSending()
        startAckListener()
    }

    @OptIn(ExperimentalStdlibApi::class)
    private fun startSending() {
        scope.launch(Dispatchers.IO) {
            for (task in sendChannel) {
                try {
                    mutex.withLock {
                        outputStreamProvider()?.apply {
                            write(task.data)
                            flush()
                        }
                    }

                    XLog.tag("Accessory Send").i("发送成功")
                    // 等待 ACK
                    val ackDeferred = CompletableDeferred<Unit>()
                    ackWaiters.send(ackDeferred)

                    val ackReceived = withTimeoutOrNull(ACK_TIMEOUT) {
                        ackDeferred.await()
                    } != null

                    task.deferred.complete(ackReceived)

                } catch (e: Exception) {
                    task.deferred.complete(false)
                    UsbFlow.updateConnectionState(ConnectionState.Error("发送失败: ${e.message}"))
                }
            }
        }
    }

    private fun startAckListener() {
        scope.launch(Dispatchers.IO) {
            UsbFlow.dataFlow.collect { packet ->
                if (PacketUtils.isAckPacket(packet)) {
                    val waiter = ackWaiters.tryReceive().getOrNull()
                    waiter?.complete(Unit)
                }
            }
        }
    }

    suspend fun sendWithAck(data: ByteArray): Boolean {
        val result = CompletableDeferred<Boolean>()
        sendChannel.send(PacketTask(data, deferred = result))
        return result.await()
    }

    suspend fun sendFile(file: File): Boolean {
        if (UsbFlow.usbConnState.value !is ConnectionState.Connected) return false

        return try {
            val fileSize = file.length()
            var chunkIndex = 0

            file.inputStream().use { fis ->
                val buffer = ByteArray(BUFFER_SIZE)

                while (true) {
                    val bytesRead = fis.read(buffer)
                    if (bytesRead <= 0) break

                    val packet = PacketUtils.buildDataPacket(
                        fileSize = fileSize,
                        chunkIndex = chunkIndex++,
                        data = buffer,
                        length = bytesRead
                    )

                    if (!sendWithAck(packet)) return false
                }

                sendWithAck(PacketUtils.buildEndPacket())
            }
            true
        } catch (e: Exception) {
            UsbFlow.updateConnectionState(ConnectionState.Error("文件发送异常: ${e.message}"))
            false
        }
    }

    fun stop() {
        sendChannel.close()
        ackWaiters.close()
    }
}
